part of '../widgets.dart';

/// 通过 validate-trigger 属性可以自定义表单校验的触发时机。
enum VanValidateTrigger {
  /// 仅在提交表单时触发校验
  onSubmit,

  /// 	在提交表单和输入框失焦时触发校验
  onBlur,

  /// 	在提交表单和输入框内容变化时触发校验
  onChange,
  ;

  static VanValidateTrigger? get(dynamic value, {Type? type, String? tag, VanValidateTrigger? orElse}) {
    return parseEnum(value, values: values, type: type, tag: tag, orElse: orElse);
  }
}

enum VanFieldValidationStatus {
  unvalidated,
  verifying,
  passed,
  failed,
  ;

  static VanFieldValidationStatus? get(dynamic value, {Type? type, String? tag, VanFieldValidationStatus? orElse}) {
    return parseEnum(value, values: values, type: type, tag: tag, orElse: orElse);
  }
}

/// 验证器规则 - 通过函数进行校验，可以返回一个 Future 来进行异步校验
/// <br> type support **[bool]** or **[String]** or **Future<Bool>** or **Future<String>**
typedef VanFieldRuleValidator<T, R> = R? Function(T value, VanFieldRule rule);
typedef _VanFieldRuleValidator1<R> = R? Function();
typedef _VanFieldRuleValidator2<T, R> = R? Function(T value);

/// 验证器规则 - 错误提示文案，可以设置为一个函数来返回动态的文案内容
typedef VanFieldRuleMessage<T> = String Function(T value, VanFieldRule rule);

/// 验证器规则 - 格式化函数，将表单项的值转换后进行校验
typedef VanFieldRuleFormatter<T, R> = R Function(T value, VanFieldRule rule);

/// 使用 Field 的 rules 属性可以定义校验规则，可选属性如下:
class VanFieldRule<T, R> {
  static final _requiredMessage = Future.value("must be required!");
  static final _patternMessage = Future.value("pattern valid error!");
  static final _validatorMessage = Future.value("validator valid error!");

  /// props - 是否为必选字段，当值为空值时（空字符串、空数组、false、undefined、null ），校验不通过
  final bool? required;

  /// props - 错误提示文案，可以设置为一个函数来返回动态的文案内容
  /// <br> **type** support **[String]** or **[VanFieldRuleMessage]**
  final dynamic message;

  /// props - 通过函数进行校验，可以返回一个 Future 来进行异步校验
  final VanFieldRuleValidator? validator;

  /// props - 通过正则表达式进行校验，正则无法匹配表示校验不通过
  final RegExp? pattern;

  /// props - 设置本项规则的触发时机，优先级高于 Form 组件设置的 validate-trigger 属性，可选值为 onChange、onBlur、onSubmit
  final VanValidateTrigger? trigger;

  /// props - 格式化函数，将表单项的值转换后进行校验
  final VanFieldRuleFormatter<T, R>? formatter;

  /// props - 设置 validator 和 pattern 是否要对空值进行校验，默认值为 true，可以设置为 false 来禁用该行为
  final bool? validateEmpty;

  Future<String?>? _getMessage<T>(value) {
    if (message is String) {
      return Future.value(message);
    } else if (message is VanFieldRuleMessage) {
      return Future.value(message!(value, this));
    }
    return null;
  }

  Future<String?> valid(dynamic value) async {
    if (isEmpty()) return null;
    if (formatter != null) value = formatter!(value, this);
    if (value == null || (value is String && value.isEmpty) || (value is List && value.isEmpty) || (value is Map && value.isEmpty)) {
      if (required == true) {
        return _getMessage(value) ?? _requiredMessage;
      }
      if (validateEmpty ?? true == false) {
        return null;
      }
    }

    if (pattern is Pattern) {
      var patternValue = value != null ? "$value" : "";
      if (!pattern!.hasMatch(patternValue)) {
        return _getMessage(patternValue) ?? _patternMessage;
      }
    }

    if (validator is VanFieldRuleValidator) {
      final rst = await Future<dynamic>.value(validator!(value, this));
      if (rst == null) return null;
      if (rst is String) return rst;
      if (rst is bool) {
        if (rst) return null;
        return _getMessage(value) ?? _validatorMessage;
      }
      _logger.e("$runtimeType.validator return-type must be [bool/String] or [Future<bool/String>]");
      return null;
    }
    return null;
  }

  bool isEmpty() {
    if (required != null) return false;
    if (message != null) return false;
    if (validator != null) return false;
    if (pattern != null) return false;
    if (trigger != null) return false;
    if (formatter != null) return false;
    if (validateEmpty != null) return false;
    return true;
  }

  const VanFieldRule({
    this.required,
    this.message,
    this.validator,
    this.pattern,
    this.trigger,
    this.formatter,
    this.validateEmpty,
  });

  static List<VanFieldRule> fromList(List rules) {
    List<VanFieldRule> rules0 = [];
    for (var rule in rules) {
      final rule0 = from(rule);
      if (rule0.isEmpty()) continue;
      rules0.add(rule0);
    }
    return rules0;
  }

  static VanFieldRule from(dynamic rule) {
    if (rule is VanFieldRule) return rule;
    if (rule is Map) return fromJson(rule);
    return const VanFieldRule();
  }

  static Future<String?> fromValid(dynamic rule, dynamic value) {
    return from(rule).valid(value);
  }

  static VanFieldRule fromJson(Map json) {
    var required = json['required'];
    if (required is! bool) required = null;

    var message = json['message'];
    if (message is! String && message is! VanFieldRuleMessage) message = null;

    var validator = json['validator'];
    if (validator is _VanFieldRuleValidator1) {
      validator = (value, VanFieldRule rule) => json['validator']();
    } else if (validator is _VanFieldRuleValidator2) {
      validator = (value, VanFieldRule rule) => json['validator'](value);
    } else if (validator is! VanFieldRuleValidator) {
      validator = null;
    }

    var pattern = json['pattern'];
    if (pattern is! Pattern) pattern = null;

    var trigger = json['trigger'];
    if (trigger is String && trigger.isNotEmpty) {
      trigger = VanValidateTrigger.get(trigger);
    } else if (trigger is! VanValidateTrigger) {
      trigger = null;
    }

    var formatter = json['formatter'];
    if (formatter is! VanFieldRuleFormatter) formatter = null;

    var validateEmpty = json['validateEmpty'];
    if (validateEmpty is! bool) validateEmpty = null;

    return VanFieldRule(
      required: required,
      message: message,
      validator: validator,
      pattern: pattern,
      trigger: trigger,
      formatter: formatter,
      validateEmpty: validateEmpty,
    );
  }
}
